package com.homelock.service;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

import com.homelock.common.config.LockInitParam;
import com.homelock.common.enumeration.LockTypeEnum;
import com.homelock.common.util.CGlibMapper;
import com.homelock.constants.DevUserRoleEnum;
import com.homelock.constants.OpmodeEnum;
import com.homelock.thread.LockRegisterAsyncTask;
import com.homelock.vo.ZxLockInfoVo;
import org.apache.commons.lang3.StringUtils;
import org.apache.tomcat.util.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import com.alibaba.fastjson.JSON;
import com.homelock.common.util.LockEncryptUtil;
import com.homelock.domain.LockIdentity;
import com.homelock.entity.HlDevInfo;
import com.homelock.entity.HlDevInfoExample;
import com.homelock.entity.HlDevInfoExample.Criteria;
import com.homelock.entity.HlDevUser;
import com.homelock.mapper.HlDevInfoMapper;
import com.pi.base.enumerate.record.RecordState;
import com.pi.base.enumerate.redis.RedisCacheEnum;
import com.pi.base.exception.ServiceException;
import com.pi.base.util.bean.ObjectTool;
import com.pi.base.util.cache.RedisUtil;
import com.pi.base.util.lang.ByteUtil;
import com.pi.base.util.lang.StringUtil;
import com.pi.uc.dao.entity.UcUserEntity;
import com.pi.uc.service.UcUserService;

@Service
public class HlDevInfoService {
  private static final Logger logger = LoggerFactory.getLogger(HlDevInfoService.class);

  private HlDevInfoMapper devInfoMapper;

  private LockUserService lockUserService;

  private HlDevUserUnlockService devUserUnlockService;

  private HlFamilyLinkageService familyLinkageService;

  private LockOpenRecordService openRecordService;

  private UcUserService userService;

  @Autowired
  private LockRegisterAsyncTask lockRegisterAsyncTask;
  @Autowired
  private LockInitParam lockInitParam;

  @Autowired
  @Lazy
  public HlDevInfoService(HlDevInfoMapper devInfoMapper, LockUserService lockUserService, UcUserService userService,
      HlDevUserUnlockService devUserUnlockService, HlFamilyLinkageService familyLinkageService,
      LockOpenRecordService openRecordService) {
    Assert.notNull(devInfoMapper, "锁具数据服务为空");
    Assert.notNull(lockUserService, "锁具用户服务为空");
    Assert.notNull(userService, "用户服务为空");
    Assert.notNull(devUserUnlockService, "用户开门方式服务为空");
    Assert.notNull(familyLinkageService, "家庭联动服务为空");
    Assert.notNull(openRecordService, "开门记录服务为空");
    this.devInfoMapper = devInfoMapper;
    this.lockUserService = lockUserService;
    this.userService = userService;
    this.devUserUnlockService = devUserUnlockService;
    this.familyLinkageService = familyLinkageService;
    this.openRecordService = openRecordService;
  }

  public Long addDevInfo(String devCode, String devName, String devImei, Long ownerId, Long sourceId,Integer devType) {
    // LockUserCheckUtil.checkLockUserAdd(devId, userId, lockUserName);
    // 校验用户是否存在
    UcUserEntity userInfo = userService.queryUserInfo(ownerId);
    // 校验设备是否存在
    HlDevInfo devInfo = getDevInfoByDevCodeOrOwnerIdIfExist(devCode, null);
    if (null != devInfo && devInfo.getState()) {
      removeDevInfo(devInfo.getId());
    }
    // 获取门锁设备证书授权缓存，如果存在，则可以注册
    LockIdentity lockIdentity;
    try {
      lockIdentity = RedisUtil.get(RedisCacheEnum.SMART_LOCK_REG_AUTH_CACHE, LockIdentity.class, devCode);
    } catch (UnsupportedEncodingException e) {
      throw new ServiceException("门锁设备证书信息获取失败,不能完成注册");
    }
    if(null == lockIdentity){
      throw new ServiceException("门锁设备证书信息获取失败,不能完成注册");
    }
    HlDevInfo record = new HlDevInfo();
    record.setDevCode(devCode);
    record.setDevName(devName);
    record.setDevImei(StringUtils.isBlank(devImei) ?"0":devImei);
    record.setOwnerId(ownerId);
    record.setSourceId(sourceId);
    record.setDevType(1);
    record.setCommunityId(0L);
    record.setVersion((long) 1);
    record
        .setCreateDate(new Date(null != lockIdentity ? lockIdentity.getRegStamp() * 1000 : System.currentTimeMillis()));
    record.setRegCode(lockIdentity.getRegCode());
    record.setUpdateDate(record.getCreateDate());
    record.setState(RecordState.STATE_NORMAL.getState());
    LockTypeEnum lockTypeEnum = Optional.ofNullable(devType).map(type->LockTypeEnum.valueOf(type)).orElse(LockTypeEnum.KEYIN_LOCK);
    if(null == lockTypeEnum){
      throw new ServiceException("锁具类型异常");
    }
    record.setDevType(lockTypeEnum.getTypeValue());
    if (null == devInfo || devInfo.getSourceId().longValue() != sourceId.longValue()) {
      devInfoMapper.insertSelective(record);
    } else {
      record.setId(devInfo.getId());
      record.setState(RecordState.STATE_NORMAL.getState());
      devInfoMapper.updateByPrimaryKeySelective(record);
    }
    // 验证该用户是否有手机号
    String mobile = StringUtils.isBlank(userInfo.getMobile()) ? "" : userInfo.getMobile();
    lockUserService.addLockUser(record.getId(),
        StringUtils.isNotBlank(userInfo.getNickName()) ? userInfo.getNickName() : "管理员",
        DevUserRoleEnum.OWNER.getRole(), record.getOwnerId(), mobile);
    // 异步向IOT注册门锁
    if(lockTypeEnum.isRegisterEnable()){
      lockRegisterAsyncTask.runRegisterLockTask(devImei, devCode,record.getSourceId());
    }else{
      logger.info("锁具不具备远程注册功能");
    }
    return record.getId();
  }

  public void removeDevInfo(String devCode, Long ownerId) {
    // LockUserCheckUtil.checkLockUserDel(devId, lockUserId);
    HlDevInfo devInfo = getDevInfo(devCode, ownerId);
    devInfoMapper.deleteByPrimaryKey(devInfo.getId());
  }

  public Long removeDevInfo(Long devId) {
    HlDevInfo devInfo = devInfoMapper.selectByPrimaryKey(devId);
    if (null == devInfo) {
      return null;
    }
    if (!devInfo.getState()) {
      return devInfo.getId();
    }
    HlDevInfo record = new HlDevInfo();
    record.setId(devInfo.getId());
    record.setState(RecordState.STATE_DELETE.getState());
    devInfoMapper.updateByPrimaryKeySelective(record);
    // 清除用户
    lockUserService.clearByDevId(devId);
    // 清除开锁方式
    devUserUnlockService.clearByDevId(devId);
    // 清除亲情关联
    familyLinkageService.clearByDevId(devId);
    // 清除开门记录
    openRecordService.clearByDevId(devId);
    return devInfo.getId();
  }

  public void updateDevInfo(String devCode, String devName, Long ownerId) {
    HlDevInfo record = getDevInfo(devCode, ownerId);
    HlDevInfo updated = new HlDevInfo();
    updated.setDevName(devName);
    updated.setVersion(record.getVersion() + 1);
    updated.setId(record.getId());
    devInfoMapper.updateByPrimaryKeySelective(record);
  }

  public void updateBatteryAndVersionById(Long id,byte battery,Long version) {
    HlDevInfo updated = new HlDevInfo();
    updated.setId(id);
    updated.setVersion(version);
    updated.setDevBattery(battery);
    devInfoMapper.updateByPrimaryKeySelective(updated);
  }
  
  public void updateDevCommunity(Long devId, Long communityId) {
    HlDevInfo record = getDevInfobyId(devId);
    HlDevInfo updated = new HlDevInfo();
    updated.setId(devId);
    updated.setCommunityId(communityId);
    updated.setState(RecordState.STATE_NORMAL.getState());
    updated.setVersion(record.getVersion() + 1);
    devInfoMapper.updateByPrimaryKeySelective(updated);
  }

  public HlDevInfo getDevInfo(String devCode, Long ownerId) {
    // LockUserCheckUtil.checkLockUserQuery(devId, userId);
    HlDevInfoExample example = new HlDevInfoExample();
    example.createCriteria().andDevCodeEqualTo(devCode).andOwnerIdEqualTo(ownerId);
    List<HlDevInfo> devUserist = devInfoMapper.selectByExample(example);
    if (CollectionUtils.isEmpty(devUserist)) {
      throw new ServiceException("LOCK_USER_NOT_EXIST");
    }
    return devUserist.get(0);
  }
  
  public HlDevInfo getDevInfoBycode(String devCode) {
      // LockUserCheckUtil.checkLockUserQuery(devId, userId);
      HlDevInfoExample example = new HlDevInfoExample();
      example.createCriteria().andDevCodeEqualTo(devCode).andStateEqualTo(RecordState.STATE_NORMAL.getState());
      List<HlDevInfo> devUserist = devInfoMapper.selectByExample(example);
      if (CollectionUtils.isEmpty(devUserist)) {
        return null;
      }
      HlDevInfo hlDevInfo = devUserist.get(0);
      Integer fngerCount = devUserUnlockService.countByDevId(hlDevInfo.getId(), OpmodeEnum.UNLOCK_FINGER);
      Integer pwdCount = devUserUnlockService.countByDevId(hlDevInfo.getId(), OpmodeEnum.UNLOCK_PASSWPRD);
      hlDevInfo.setFingerUsed(null != fngerCount? fngerCount.shortValue() : 0);
      hlDevInfo.setPwdUsed(null != pwdCount? pwdCount.shortValue() : 0);
      return hlDevInfo;
    }

  /**
   * 振兴锁的信息新增卡使用数量
   * @param devCode
   * @return
   */
  public ZxLockInfoVo getZxDevInfoBycode(String devCode) {
    HlDevInfo hlDevInfo = getDevInfoBycode(devCode);
    if(hlDevInfo == null){
      return null;
    }
    // 查询卡使用数量
    ZxLockInfoVo zxLockInfoVo = CGlibMapper.mapper(hlDevInfo,ZxLockInfoVo.class);
    Integer cardCount = devUserUnlockService.countByDevId(hlDevInfo.getId(), OpmodeEnum.UNLOCK_CARD);
    zxLockInfoVo.setCardUsed(Optional.ofNullable(cardCount).orElse(0).shortValue());
    return zxLockInfoVo;
  }

  private HlDevInfo getDevInfoByDevCodeOrOwnerIdIfExist(String devCode, Long ownerId) {
    if (StringUtils.isBlank(devCode) && (null == ownerId || ownerId <= 0)) {
      throw new ServiceException("PARAM_IS_EMPTY");
    }
    HlDevInfoExample example = new HlDevInfoExample();
    Criteria criteria = example.createCriteria();
    if (StringUtils.isNotBlank(devCode)) {
      criteria.andDevCodeEqualTo(devCode);
    }
    if (null != ownerId) {
      criteria.andOwnerIdEqualTo(ownerId);
    }
    List<HlDevInfo> devInfoList = devInfoMapper.selectByExample(example);
    if (CollectionUtils.isEmpty(devInfoList)) {
      return null;
    }
    return devInfoList.get(0);
  }

  public List<HlDevInfo> getDevInfo(Long ownerId) {
    // LockUserCheckUtil.checkLockUserQuery(devId, userId);
    HlDevInfoExample example = new HlDevInfoExample();
    example.createCriteria().andOwnerIdEqualTo(ownerId);
    List<HlDevInfo> devIfoList = devInfoMapper.selectByExample(example);
    return devIfoList;
  }

  public List<HlDevInfo> getDevInfoAndCommunityNotNull(Long ownerId) {
    HlDevInfoExample example = new HlDevInfoExample();
    example.createCriteria().andOwnerIdEqualTo(ownerId).andCommunityIdNotEqualTo(0L).andCommunityIdIsNotNull()
    .andStateEqualTo(RecordState.STATE_NORMAL.getState());
    List<HlDevInfo> devIfoList = devInfoMapper.selectByExample(example);
    return devIfoList;
  }

  public List<HlDevInfo> getDevInfoByIds(List<Long> ids) {
    if (CollectionUtils.isEmpty(ids)) {
      return new ArrayList<>(0);
    }
    HlDevInfoExample example = new HlDevInfoExample();
    example.createCriteria().andIdIn(ids).andStateEqualTo(RecordState.STATE_NORMAL.getState());
    List<HlDevInfo> devIfoList = devInfoMapper.selectByExample(example);
    return devIfoList;
  }

  public HlDevInfo getDevInfobyId(long id) {
    HlDevInfo devInfo = getDevInfobyIdIfExist(id);
    if (null == devInfo) {
      throw new ServiceException("LOCK_INFO_NOT_EXIST");
    }
    Integer fngerCount = devUserUnlockService.countByDevId(devInfo.getId(), OpmodeEnum.UNLOCK_FINGER);
    Integer pwdCount = devUserUnlockService.countByDevId(devInfo.getId(), OpmodeEnum.UNLOCK_PASSWPRD);
    devInfo.setFingerUsed(null != fngerCount? fngerCount.shortValue() : 0);
    devInfo.setPwdUsed(null != pwdCount? pwdCount.shortValue() : 0);
    return devInfo;
  }

  public HlDevInfo getDevInfobyIdIfExist(long id) {
    HlDevInfoExample example = new HlDevInfoExample();
    example.createCriteria().andIdEqualTo(id).andStateEqualTo(RecordState.STATE_NORMAL.getState());
    List<HlDevInfo> devUserist = devInfoMapper.selectByExample(example);
    return ObjectTool.getOne(devUserist);
  }

  /**
   * 根据imei查询设备信息
   * 
   * @param imei
   * @return
   */
  public HlDevInfo getDevInfoByImei(String imei) {
    HlDevInfoExample example = new HlDevInfoExample();
    example.createCriteria().andDevImeiEqualTo(imei);
    List<HlDevInfo> devUserist = devInfoMapper.selectByExample(example);
    if (CollectionUtils.isEmpty(devUserist)) {
      return null;
    }
    return devUserist.get(0);
  }

  /**
   * 根据imei查询设备信息
   *
   * @param devCode
   * @return
   */
  public HlDevInfo findOneByDevCodeAndStateTrue(String devCode) {
    HlDevInfoExample example = new HlDevInfoExample();
    example.createCriteria().andDevCodeEqualTo(devCode).andStateEqualTo(RecordState.STATE_NORMAL.getState());
    List<HlDevInfo> devUserist = devInfoMapper.selectByExample(example);
    if (CollectionUtils.isEmpty(devUserist)) {
      return null;
    }
    return devUserist.get(0);
  }

  public LockIdentity getCipherIdentityCode(Long devId, Long loginUserId) {
    HlDevInfo devInfo = getDevInfobyId(devId);
    HlDevUser devUser = lockUserService.queryLockUserByAppUserId(devId, loginUserId);
    if (null == devUser) {
      throw new ServiceException("当前账号不是门锁用户");
    }
    try {
      byte[] lockId = ByteUtil.hexToByte(devInfo.getDevCode());
      Long time = devInfo.getCreateDate().getTime() / 1000;
      byte[] lockIdentity = LockEncryptUtil.getDevIdentity(lockId, devInfo.getRegCode(), time);
      String lockIdentityCode = Base64.encodeBase64String(LockEncryptUtil.getCiperedDevCode(
          LockEncryptUtil.getDevCode(lockId, loginUserId), LockEncryptUtil.getCiperedDevIdentity(lockIdentity,lockInitParam.getSecretkeyByte())));
      LockIdentity id = new LockIdentity();
      id.setRegCode(devInfo.getRegCode());
      id.setLockIdentityCode(lockIdentityCode);
      id.setRegStamp(devInfo.getCreateDate().getTime() / 1000);
      return id;
    } catch (Exception e) {
      logger.error("", e);
      throw new ServiceException("获取失败");
    }

  }

  public LockIdentity getCipherIdentityCode(String devCode, String imei, Long loginUserId) {
    try {
        String regCode = StringUtil.generateNonce(4);
      byte[] lockId = ByteUtil.hexToByte(devCode);
      Long time = System.currentTimeMillis() / 1000;
      byte[] lockIdentity = LockEncryptUtil.getDevIdentity(lockId, regCode, time);
      byte[] initialIdentity = LockEncryptUtil.getDevIdentity(lockId, new String(ByteUtil.hexToByte("00000000")), 0L);
      String lockIdentityCode = Base64.encodeBase64String(LockEncryptUtil.getCiperedDevCode(
          LockEncryptUtil.getDevCode(lockId, loginUserId), LockEncryptUtil.getCiperedDevIdentity(lockIdentity,lockInitParam.getSecretkeyByte())));
      String initialLockIdentityCode = Base64.encodeBase64String(LockEncryptUtil.getCiperedDevCode(
          LockEncryptUtil.getDevCode(lockId, loginUserId), LockEncryptUtil.getCiperedDevIdentity(initialIdentity,lockInitParam.getSecretkeyByte())));
      LockIdentity id = new LockIdentity();
      
      id.setRegCode(regCode);
      id.setLockIdentityCode(lockIdentityCode);
      id.setRegStamp(time);
      id.setInitialIdentityCode(initialLockIdentityCode);
      RedisUtil.directset(RedisCacheEnum.SMART_LOCK_REG_AUTH_CACHE, JSON.toJSONString(id), devCode);
      return id;
    } catch (Exception e) {
      logger.error("", e);
      throw new ServiceException("获取失败");
    }
  }

  /**
   * 查询社区关联设备
   * @param communityId
   * @return
   */
  public List<HlDevInfo> queryListByCommunityId(long communityId){
    HlDevInfoExample hlDevInfoExample = new HlDevInfoExample();
    hlDevInfoExample.createCriteria().andCommunityIdEqualTo(communityId).andStateEqualTo(RecordState.STATE_NORMAL.getState());
    List<HlDevInfo> list = devInfoMapper.selectByExample(hlDevInfoExample);
    return list;
  }

public void updateLockMode(Long devId, Integer mode) {
    if(null == devId) {
        throw new ServiceException("设备编号为空");
    }
    if(null == mode) {
        throw new ServiceException("门锁当前工作模式为空");
    }
    if(mode < 0 || mode> 1) {
        throw new ServiceException("工作模式错误"); 
    }
    HlDevInfo devInfo = devInfoMapper.selectByPrimaryKey(devId);
    if(null == devInfo || !Objects.equals(devInfo.getState(), RecordState.STATE_NORMAL.getState())) {
        throw new ServiceException("门锁不存在"); 
    }
    HlDevInfo record = new HlDevInfo();
    record.setDevMode(mode);
    record.setId(devInfo.getId());
    devInfoMapper.updateByPrimaryKeySelective(record);
}


}
